class_name Player extends CharacterBody2D

enum Direction {
	LEFT = -1,
	RIGHT = 1,
}

var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity")

@onready var animation_player: AnimationPlayer = $AnimationPlayer
@onready var graphics: Node2D = $Graphics

@onready var coyote_timer: Timer = $Timers/CoyoteTimer
@onready var just_request_timer: Timer = $Timers/JustRequestTimer
@onready var hand_checker: RayCast2D = $Graphics/HandChecker
@onready var foot_checker: RayCast2D = $Graphics/FootChecker

@onready var attack_request_timer: Timer = $Timers/AttackRequestTimer

@onready var sliding_request_timer: Timer = $Timers/SlidingRequestTimer

@onready var status_machine: Node = $StatusMachine

# 无敌时间
@onready var invincible_timer: Timer = $Timers/InvincibleTimer

var interact_with:Array[Interactable]
@onready var animated_sprite_icon: AnimatedSprite2D = $AnimatedSpriteIcon

@onready var status_pannel: HBoxContainer = $CanvasLayer/StatusPannel
@onready var blackboard: PlayerBlackBoard = $BlackBoard

func _ready():
	blackboard = Game.player_blackboard
	blackboard.set_actor(self)
	
	status_pannel.load(blackboard.get_stats())
	
	status_machine.blackboard = blackboard
	status_machine.actor = self
	status_machine.load_child()
	
	status_machine.start_status_node("Idle")

func _process(delta: float) -> void:
	# 可交互对象
	animated_sprite_icon.visible = not interact_with.is_empty()
	if invincible_timer.time_left>0:
		graphics.modulate.a = sin(Time.get_ticks_msec()/20) * 0.5 + 0.5
		
	status_machine.run_process(delta)
	
func _physics_process(delta: float) -> void:
	status_machine.run_physics_process(delta)
	
####################### 事件处理
# 用户输入
func _unhandled_input(event: InputEvent) -> void:
	# Handle jump.
	if Input.is_action_just_pressed("jump"):
		just_request_timer.start()
		
	if Input.is_action_just_released("jump"):
		just_request_timer.stop()
		if velocity.y < blackboard.JUMP_VELOCITY / 3:
			velocity.y = blackboard.JUMP_VELOCITY * just_request_timer.time_left / just_request_timer.wait_time
	# 攻击
	if Input.is_action_just_pressed("attack"):
		attack_request_timer.start()
		
	# 滑动无敌
	if Input.is_action_just_pressed("sliding"):
		sliding_request_timer.start()
		
	# 交互键
	if Input.is_action_just_pressed("interact") and not interact_with.is_empty():
		interact_with.back().interact()
		
	# 滑动无敌
	if Input.is_action_just_pressed("ui_up"):
		print(position)

		
	# 暂停
	if Input.is_action_just_pressed("pause"):
		Game.to_game_pause()

func register_interact_with(act :Interactable):
	if status_machine.is_status("Death"):
		return
		
	if act in interact_with:
		return
	interact_with.append(act)
		
func unregister_interact_with(act :Interactable):
	interact_with.erase(act)

func can_jump() -> bool:
	if just_request_timer.get_time_left()>0 == false:
		return false
	var can_jump = is_on_floor() or coyote_timer.get_time_left() > 0
	if can_jump:
		just_request_timer.stop()
		coyote_timer.stop()
		return true
	return false
	
func can_jump_on_wall() -> bool:
	if is_on_wall() && just_request_timer.get_time_left()>0:
		just_request_timer.stop()
		return true
	return false

func can_wall_slide() -> bool:
	return is_on_wall() && hand_checker.is_colliding() && foot_checker.is_colliding()

func can_sliding() -> bool:
	return blackboard.has_enough_energy() && is_on_floor() && sliding_request_timer.get_time_left()>0 && not foot_checker.is_colliding()
	
func can_attack(stage:int = 1) -> bool:
	if stage == 1:
		return attack_request_timer.time_left > 0
	elif stage > 1:
		return attack_request_timer.time_left > 0
	return false

func get_direction()->int:
	return Input.get_axis("move_left", "move_right")
	
############################ end 事件处理

func refresh_face_direction() -> void:	# 转向
	if velocity.x != 0:
		graphics.scale.x = -1 if velocity.x<0 else 1

func face_direction(direction:int) -> void:	# 转向
	graphics.scale.x = direction
	
func get_face_direction()->int:
	return graphics.scale.x
		
func move_and_collision_info():
	var collision_info = get_collision_info()
	is_just_to_floor(collision_info)
	return collision_info
	# 刚刚落地
	
func is_just_to_floor(collision_info):
	if collision_info.get("was_on_floor") and not collision_info.get("is_on_floor"):
		# 离地时刻
		coyote_timer.start()
		
func get_collision_info():
	var info :Dictionary
	info.was_on_floor = is_on_floor()
	info.was_on_wall = is_on_wall()
	info.was_on_celling = is_on_ceiling_only()
	info.last_velocity = velocity
	
	move_and_slide()
	
	info.is_on_floor = is_on_floor()
	info.is_on_wall = is_on_wall()
	info.is_on_celling = is_on_ceiling_only()
	return info

####################### start 播放动画
func play_animation(name:String) ->void:
	name = name.to_lower()
	animation_player.play(name)
	
func is_play_animation(name) -> bool:
	return animation_player.current_animation == name.to_lower() && animation_player.is_playing()

####################### end 播放动画

######################### start 伤害处理
func _on_hurtbox_hurt(hitbox: Hitbox) -> void:
	if invincible_timer.time_left>0:
		return
	invincible_timer.start()
	var pending_damage = blackboard.create_damage(hitbox.owner,1,1)
	update_health(pending_damage.amount)

func update_health(v:int)->int:
	var health:int = blackboard.update_health(v)
	if health <= 0:
		invincible_timer.stop()
		interact_with.clear()
		status_machine.change_status("Death")
	else:
		status_machine.change_status("Hurt")
	return health

func _on_invincible_timer_timeout() -> void:
	graphics.modulate.a = 1.0

# 动画专用
func to_death():
	queue_free()
	Game.to_game_over()
	
	#Game.reload_scene()
######################### end 伤害处理

func _on_hitbox_hit(hurtbox: Hurtbox) -> void:
	Game.shake_camera(2.0)
